/*

Copyright (C) 2008 Victor Manuel Sanchez Cartagena, Juan Antonio Perez Ortiz


This file is part of ANTLRArbol.

ANTLRArbol is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

ANTLRArbol is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. 

*/

package org.ANTLRArbol.lib;

import java.util.Hashtable;
import java.util.Set;
import java.util.ArrayList;
import org.ANTLRArbol.grammars.Java.*;
import org.antlr.runtime.*; 

/**
 * Contains some useful static methods
 * 
 * @author vitaka
 *
 */
public class AuxiliaryCodeANTLRArbol {
	
	/**
	 * Adds new dependencies to the dependency graph
	 * This method is called by the modified grammar
	 * 
	 * @param varLeft Variables that depends on varRight.
	 * @param varRight varLeft depends on these variables.
	 * @param dependencyGraph Dependency graph that will be updated with the nre dependencies.
	 * @param keepsValue True if the variables in varLeft will keep teir previous dependencies
	 * @param scope Scope of the variables
	 */
	public static void processDependency(Set<String> varLeft, Set<String> varRight,DependenciesGraphANTLRArbol dependencyGraph, boolean keepsValue, int scope)
	{
		for(String vIzq: varLeft)
		{
			
			
			if(!keepsValue && !varRight.contains(vIzq))
				dependencyGraph.removeDependencies(vIzq,scope);
			
			for(String vDer: varRight)
			{
				
				dependencyGraph.addDependency(vIzq, vDer,scope);				
			}
			
		}
	}
	
	/**
	 * Returns the variables present in each expression of the list
	 * This method is called by the ANTLR grammar.
	 * 
	 * @param list A list of expressions separated by commas
	 * @return A list of sets. Each position of the list contains the set of variables that appear in the corresponding expression  
	 */
	public static ArrayList<Set<String>> processExpressionList(String list)
	{
		ArrayList<Set<String>> retorno = new ArrayList<Set<String>>(); 
		CharStream input = new ANTLRStringStream(list);
		JavaLexer lex = new JavaLexer(input);
		CommonTokenStream tokens = new CommonTokenStream(lex);
		JavaParser parser = new JavaParser(tokens);
		try
		{
			
			parser.expresionesSepComas();
			//System.out.println("Traduccion:\n"+parser.getTraduccion());
			retorno= parser.getListaExpresiones();			
		}
		catch(RecognitionException e)
		{
			System.err.println("Error while processing expression list");
			e.printStackTrace();
		}
		
		
		
		return retorno;
	}
	
	/**
	 * 
	 * Modifies a block of java code, adding instructions to detect dependencies between variables.
	 * Uses the Java grammar.
	 * This method is called by the ANTLR grammar.
	 * 
	 * @param block block of Java code
	 * @param scope scope where the block starts
	 * @return A modified version of the input block.
	 */
	public static String processBlock(String block, int scope)
	{
		
		if(block.charAt(block.length()-1)!='?')
		{
			CharStream input = new ANTLRStringStream(block);
			JavaLexer lex = new JavaLexer(input);
			CommonTokenStream tokens = new CommonTokenStream(lex);
			JavaParser parser = new JavaParser(tokens);
			try
			{
				
				parser.setAmbito(scope-1);
				parser.bloque();
				
				String traduccion= parser.getTraduccion();
				
				return traduccion;
			}
			catch(RecognitionException e)
			{
				System.err.println("Error al procesar el bloque");
				e.printStackTrace();
				return block;
			}
		}
		else
			return block;
	}
	
	/**
	 * Tells the AttributeTree which are the dependencies of a inherited attribute.
	 * 
	 * This method is called by the modified grammar.
	 * 
	 * @param variableName Name of the variable assigned to the attribute, whose dependencies will be calculated.
	 * @param variableNumber Number of the inherited attribute whose dependencies have to be calculated.
	 * @param attributeTree Instance of AttributeTreeANTLRArbol
	 * @param inheritedSon The inherited attribute whose depndencies have to be calculated belong to this node.
	 * @param inheritedFather Father node of "inheritedSon"
	 * @param dependencyGraph Used to detect the dependencies.
	 * @param scope Scope of the variable assigned to the inherited attribute.
	 */
	public static void detectDependencyInherited(String variableName, int variableNumber, AttributeTreeANTLRArbol attributeTree, ArrayList<String> inheritedSon, ArrayList<String> inheritedFather ,DependenciesGraphANTLRArbol dependencyGraph , int scope )
	{	
		
		
		
		String nombreAtributo = inheritedSon.get(variableNumber);
		
		Set<String> dependientes = dependencyGraph.getVariablesThatDepends(variableName,scope);
		for(String dependiente:dependientes)
		{
			if(dependiente.startsWith("["))
			{
				String[] pedazos = dependiente.split("\\.");
				attributeTree.addInheritedDependencySibling(pedazos[0].substring(1), pedazos[1],nombreAtributo);
			}
			else
			if(dependiente.startsWith("$"))
			{
				if(inheritedFather.contains(dependiente.substring(1)))
				{
					attributeTree.addInheritedDependencyFather(dependiente.substring(1),nombreAtributo );
				}
			}
		}
		
		
	}
	
	/**
	 * Tells the AttributeTree which are the dependencies of a synthesized attribute
	 * This method is called by the modified grammar.
	 * 
	 * @param var Synthesized attribute whose dependencias have to be calculated
	 * @param dependencyGraph Used to detect the dependencies.
	 * @param attributeTree Instance of AttributeTreeANTLRArbol
	 */
	public static void detectDependencySynthesized(String var, DependenciesGraphANTLRArbol dependencyGraph, AttributeTreeANTLRArbol attributeTree )
	{
		Set<String >dependencias = dependencyGraph.getVariablesThatDepends(var,0);
		for(String dependencia: dependencias)
		{
			if(dependencia.startsWith("["))
			{
				String[] pedazos = dependencia.split("\\.",2);
				if(pedazos.length==2)
				{
					String nombreNodo = pedazos[0].substring(1);
					String atributo = pedazos[1];
					attributeTree.addSynthesizedDependency(nombreNodo, atributo,var.substring(1));
				}
			}
		}
	}
	
	/**
	 * Replaces "%" by "\\%" to avoid problems with strings in ANTLR:
	 * 
	 * @param input String to be escaped 
	 * @return Modified input string
	 */
	public static String escape(String input)
	{
		String retorno = input.replace("%", "\\%");
		return retorno;
	}
	
}